package Punto;

import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JLabel;

import spread.AdvancedMessageListener;
import spread.SpreadConnection;
import spread.SpreadException;
import spread.SpreadGroup;
import spread.SpreadMessage;
import Mensajes.Mensaje_Num_Paneles;
import Mensajes.Mensaje_Punto_Monitorizacion;
import Operaciones.Constantes;

public class PanelPunto extends Panel implements AdvancedMessageListener, Observer{
	private static final long serialVersionUID = 3095155158733993182L;
	
	private JLabel info = new JLabel("");
	private InfoPanel infoPanel = new InfoPanel();
	
	private JLabel titleArrival = new JLabel ("Paneles de llegadas");
	private JLabel infoArrival = new JLabel ("");

	private JLabel titleDeparture = new JLabel ("Paneles de salidas");
	private JLabel infoDeparture = new JLabel ("");
	
	private JLabel titleTerminal = new JLabel ("Terminales");
	private JLabel infoTerminal = new JLabel ("");
	
	private JLabel titlePunto = new JLabel ("Puntos de monitorización");
	private JLabel infoPunto = new JLabel ("");
	
	// Grupos de Spread
	private SpreadGroup groupLlegadas;
	private SpreadGroup groupSalidas;
	private SpreadGroup groupTerminal;
	private SpreadGroup groupPunto;
	
	// Conexion con Spread
	private SpreadConnection connection;
	
	public PanelPunto (String pnombrePanel, int puerto)
	{
		super(pnombrePanel);
		
	    // Este panel observará cambios en los paneles.
	    infoPanel.addObserver(this);
		
		this.setSize(Constantes.ANCHO_VENTANA_MONITOR,Constantes.ALTO_VENTANA_MONITOR);
		this.setLayout(new GridBagLayout());
		inicializarPanel();
	    this.setVisible(true);
	    
	    // Creamos al conexion con Spread
	    this.connection = new SpreadConnection();
	    try {
			this.connection.connect(null, puerto, pnombrePanel, false, true);
			this.connection.add(this);
			
			// Me agrego a todos los grupos para que me lleguen todo tipo de mensajes.
			groupLlegadas = new SpreadGroup();
			groupSalidas = new SpreadGroup();
			groupTerminal = new SpreadGroup();
			groupPunto = new SpreadGroup();

			groupLlegadas.join(connection, Constantes.GRUPO_LLEGADAS);
			groupSalidas.join(connection, Constantes.GRUPO_SALIDAS);
			groupTerminal.join(connection, Constantes.GRUPO_TERMINAL);
			groupPunto.join(connection, Constantes.GRUPO_PUNTO);

		} catch (SpreadException e) {
			Constantes.mensajeError("Problema al crear la conexion con Spread (Punto de monitorización)");
			System.exit(-1);
		}
		// Fin conexión con Spread
	}
	protected void inicializarPanel() {
		this.setBackground(Color.BLACK);

		GridBagConstraints c = new GridBagConstraints();
		
		c.weightx = 1.0; c.weighty = 1.0;
		c.fill = GridBagConstraints.NONE;
		c.anchor = GridBagConstraints.CENTER;
		
		c.gridx = 0;
		c.gridy = 0;
			this.titleDeparture.setForeground(Color.YELLOW);
			Font auxFont = this.titleDeparture.getFont(); 
			this.titleDeparture.setFont(new Font(auxFont.getFontName(), auxFont.getStyle(), Constantes.TAM_LETRA_PANEL));
			
			this.add(this.titleDeparture,c);
			
		c.gridx = 0;
		c.gridy = 1;
			this.infoDeparture.setForeground(Color.WHITE);
			this.add(this.infoDeparture,c);
		
		c.gridx = 0;
		c.gridy = 2;
			this.titleArrival.setForeground(Color.YELLOW);
			Font auxFont2 = this.titleArrival.getFont(); 
			this.titleArrival.setFont(new Font(auxFont2.getFontName(), auxFont.getStyle(), Constantes.TAM_LETRA_PANEL));
			
			this.add(this.titleArrival,c);
					
		c.gridx = 0;
		c.gridy = 3;
			this.infoArrival.setForeground(Color.WHITE);
			this.add(this.infoArrival,c);
			
		c.gridx = 0;
		c.gridy = 4;
			this.titleTerminal.setForeground(Color.YELLOW);
			this.add(this.titleTerminal,c);
			
			Font auxFont3 = this.titleTerminal.getFont(); 
			this.titleTerminal.setFont(new Font(auxFont3.getFontName(), auxFont.getStyle(), Constantes.TAM_LETRA_PANEL));
			
		c.gridx = 0;
		c.gridy = 5;
			this.infoTerminal.setForeground(Color.WHITE);
			this.add(this.infoTerminal,c);
			
		c.gridx = 0;
		c.gridy = 6;
			this.titlePunto.setForeground(Color.YELLOW);
			this.add(this.titlePunto,c);
				
			Font auxFont4 = this.titlePunto.getFont(); 
			this.titlePunto.setFont(new Font(auxFont4.getFontName(), auxFont4.getStyle(), Constantes.TAM_LETRA_PANEL));
				
		c.gridx = 0;
		c.gridy = 7;
			this.infoPunto.setForeground(Color.WHITE);
			this.add(this.infoPunto,c);

		// Nos damos de alta como un punto de monitorización.
		Componente p = new Componente(Constantes.GRUPO_PUNTO,this.nombrePanel, Constantes.FUNCIONANDO);
		this.infoPanel.addGrupo_Punto(p);
			
		this.setVisible(true);
	}
	
	public void setMensaje (String mensaje){
		String aux = this.info.getText() + mensaje;
		this.info.setText(aux);
	}
	
	// Implementamos el método que me llamará cuando me llame el objeto observador.
	public void update(Observable ob, Object o) {
		if (ob != null){
			InfoPanel i = (InfoPanel)ob;

			this.infoArrival.setText(i.toStringHTML_Arrival());
			this.infoDeparture.setText(i.toStringHTML_Departure());
			this.infoTerminal.setText(i.toStringHTML_Terminal());
			this.infoPunto.setText(i.toStringHTML_Punto());
		}
	}
	
	public boolean sendMessage_Punto (){
		// Creamos el mensaje de envio
		SpreadMessage msg = new SpreadMessage();
		try {
			// Creamos el Mensaje de estado asociado a este envio.
			Mensaje_Punto_Monitorizacion me = new Mensaje_Punto_Monitorizacion(this.infoPanel);
			msg.setObject(me);
			msg.setSafe();
			msg.setSelfDiscard(true);
			msg.addGroup(this.groupPunto);
			connection.multicast(msg);
		} catch (SpreadException e) {
			Constantes.mensajeError("Problema al enviar mensaje al grupo de Terminales");
			return false;
		}
		return true;
	}
	
	/////////////////////////////////////////////////////////////////////////////////
	// Implementamos los metodos necesarios para la interfaz AdvancedMessageListener
	/////////////////////////////////////////////////////////////////////////////////

	public void regularMessageReceived(SpreadMessage msg){
		String nameMsg = msg.getSender().toString().split("#")[1];
		if (nameMsg.startsWith("PP")){
			Mensaje_Punto_Monitorizacion panelInfo = null;
			try {
				panelInfo = (Mensaje_Punto_Monitorizacion) msg.getObject();
				InfoPanel i_aux = panelInfo.getInfo();
				
				// Establecemos todo la información que recibimos.
				this.infoPanel.setGrupo_Arrivals(i_aux.getlC_Group_Arrivals());
				this.infoPanel.setGrupo_Departure(i_aux.getlC_Group_Departure());
				this.infoPanel.setGrupo_Punto(i_aux.getlC_Group_Punto());
				this.infoPanel.setGrupo_Terminal(i_aux.getlC_Group_Terminal());
			} catch (SpreadException e) {
				Constantes.mensajeError("Problema al recibir mensaje de Spread");
			}
		} else if (nameMsg.startsWith("PA")){
				Mensaje_Num_Paneles panelArrival;
				try {
					panelArrival = (Mensaje_Num_Paneles) msg.getObject();
				
				
					boolean estadoPanel = panelArrival.getEncendido();
					Componente c;
					if (estadoPanel){
						c = new Componente(Constantes.GRUPO_LLEGADAS,nameMsg, Constantes.FUNCIONANDO);
					} else {
						c = new Componente(Constantes.GRUPO_LLEGADAS,nameMsg, Constantes.REPOSO);
					}
					
					this.infoPanel.addGrupo_Arrivals(c);
				} catch (SpreadException e) {
					Constantes.mensajeError("Problema al recibir un mensaje regular");
				}
		} else if (nameMsg.startsWith("PD")){
			Mensaje_Num_Paneles panelDeparture;
			try {
				panelDeparture = (Mensaje_Num_Paneles) msg.getObject();
			
				boolean estadoPanel = panelDeparture.getEncendido();
				Componente c;
				if (estadoPanel){
					c = new Componente(Constantes.GRUPO_SALIDAS,nameMsg, Constantes.FUNCIONANDO);
				} else {
					c = new Componente(Constantes.GRUPO_SALIDAS,nameMsg, Constantes.REPOSO);
				}
				
				this.infoPanel.addGrupo_Departure(c);
			} catch (SpreadException e) {
				Constantes.mensajeError("Problema al recibir un mensaje regular");
			}
		} else if (nameMsg.startsWith("TER")){
			Componente c = new Componente(Constantes.GRUPO_TERMINAL,nameMsg, Constantes.FUNCIONANDO);
			this.infoPanel.addGrupo_Terminal(c);
		}
	}

	public void membershipMessageReceived(SpreadMessage msg){
		if (msg.getMembershipInfo().isCausedByJoin()){
			// Si el mensaje es causado por una conexion tendré que añadir a la lista de monitores.
			if (msg.getMembershipInfo().getGroup().toString().equals(Constantes.GRUPO_LLEGADAS)){
				
				String nameAdd = msg.getMembershipInfo().getJoined().toString();
				String [] listSplit = nameAdd.split("#");
				if (! listSplit[1].equals(this.nombrePanel) && (listSplit[1].startsWith("PA"))){
					Componente c = new Componente(msg.getMembershipInfo().getGroup().toString(),listSplit[1], Constantes.FUNCIONANDO);
					this.infoPanel.addGrupo_Arrivals(c);
				}
				
			} else if (msg.getMembershipInfo().getGroup().toString().equals(Constantes.GRUPO_SALIDAS)) {
				
				String nameAdd = msg.getMembershipInfo().getJoined().toString();
				String [] listSplit = nameAdd.split("#");
				if (! listSplit[1].equals(this.nombrePanel) && (listSplit[1].startsWith("PD"))){
					Componente c = new Componente(msg.getMembershipInfo().getGroup().toString(),listSplit[1], Constantes.FUNCIONANDO);
					this.infoPanel.addGrupo_Departure(c);
				}
				
			} else if (msg.getMembershipInfo().getGroup().toString().equals(Constantes.GRUPO_TERMINAL)){
				
				String nameAdd = msg.getMembershipInfo().getJoined().toString();
				String [] listSplit = nameAdd.split("#");
				if (! listSplit[1].equals(this.nombrePanel) && (listSplit[1].startsWith("TER"))){
					Componente c = new Componente(msg.getMembershipInfo().getGroup().toString(),listSplit[1], Constantes.FUNCIONANDO);
					this.infoPanel.addGrupo_Terminal(c);
				}
			} else if (msg.getMembershipInfo().getGroup().toString().equals(Constantes.GRUPO_PUNTO)){
				
				String nameAdd = msg.getMembershipInfo().getJoined().toString();
				String [] listSplit = nameAdd.split("#");
				if (! listSplit[1].equals(this.nombrePanel) && (listSplit[1].startsWith("PP"))){
					Componente c = new Componente(msg.getMembershipInfo().getGroup().toString(),listSplit[1], Constantes.FUNCIONANDO);
					this.infoPanel.addGrupo_Punto(c);
					
					if (!(sendMessage_Punto()))
						Constantes.mensajeError("Problema al enviar mensaje hacia los puntos de monitorización");	
				}
			}
			
		} else if (msg.getMembershipInfo().isCausedByDisconnect()){
			// Si el mensaje es causado por una conexion tendré que eliminar a la lista y volver pintar.
			if (msg.getMembershipInfo().getGroup().toString().equals(Constantes.GRUPO_LLEGADAS)){
				
				String nameDel = msg.getMembershipInfo().getDisconnected().toString();
				String [] listSplit = nameDel.split("#");
				Componente c = new Componente(msg.getMembershipInfo().getGroup().toString(),listSplit[1], Constantes.APAGADO);
				this.infoPanel.deleteGrupo_Arrivals(c);
				
			} else if (msg.getMembershipInfo().getGroup().toString().equals(Constantes.GRUPO_SALIDAS)) {
				
				String nameDel = msg.getMembershipInfo().getDisconnected().toString();
				String [] listSplit = nameDel.split("#");
				Componente c = new Componente(msg.getMembershipInfo().getGroup().toString(),listSplit[1], Constantes.APAGADO);
				this.infoPanel.deleteGrupo_Departure(c);
				
			} else if (msg.getMembershipInfo().getGroup().toString().equals(Constantes.GRUPO_TERMINAL)){
				
				String nameDel = msg.getMembershipInfo().getDisconnected().toString();
				String [] listSplit = nameDel.split("#");
				Componente c = new Componente(msg.getMembershipInfo().getGroup().toString(),listSplit[1], Constantes.APAGADO);
				this.infoPanel.deleteGrupo_Terminal(c);
				
			} else if (msg.getMembershipInfo().getGroup().toString().equals(Constantes.GRUPO_PUNTO)){
				
				String nameDel = msg.getMembershipInfo().getDisconnected().toString();
				String [] listSplit = nameDel.split("#");
				Componente c = new Componente(msg.getMembershipInfo().getGroup().toString(),listSplit[1], Constantes.APAGADO);
				this.infoPanel.deleteGrupo_Punto(c);
				
			}
		}
			
	}
	//////////////////////////////////////////////////////////
	// Fin de la implementación de los métodos de la interfaz
	//////////////////////////////////////////////////////////
	
	public ArrayList <Componente> getComponentes(SpreadMessage msg){
		
		ArrayList <Componente> list_aux = new ArrayList<Componente>();
		
		SpreadGroup [] g = msg.getMembershipInfo().getMembers();
		for (int i = 0; i < g.length; i++){
			String [] listSplit = g[i].toString().split("#");
			Componente c = new Componente(msg.getMembershipInfo().getGroup().toString(),listSplit[1],  Constantes.FUNCIONANDO);
			list_aux.add(c);
		}
		
		return list_aux;
	}
	
	
	// Creamos el programa principal que lanzara los paneles
	public static void main(String args[]){
		String nombrePanel = "";
		int puerto = 0;
		try{
			// Cogemos el nombre del panel.
			nombrePanel = args[0];
			// Cogemos el argumento que será el puerto.
			puerto = Integer.parseInt(args[1]);
		}catch (NumberFormatException e ){
			Constantes.mensajeError("No válido el puerto introducido");
			System.exit(-1);
		}catch (java.lang.ArrayIndexOutOfBoundsException e ){
			Constantes.mensajeError("Debes de intrucir como argumento el puerto de ejecución");
			System.exit(-1);
		}
		// Creamos los el panel de llegadas
		PanelPunto pM = new PanelPunto(nombrePanel, puerto);

		new VentanaPunto(pM,"Punto de monitorización - " + nombrePanel);
	}
}
